package net.oschina.simpleplus.erpc.producer;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;
import java.util.UUID;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.protobuf.GeneratedMessageV3;
import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.GeneratedMessageV3.Builder;

import net.oschina.simpleplus.erpc.Launcher;
import net.oschina.simpleplus.erpc.api.ERpc;
import net.oschina.simpleplus.erpc.core.ERpcRequestEntity;
import net.oschina.simpleplus.erpc.support.ProtobufCache;

public class ERpcProxy {
	
	private static final Logger logger = LoggerFactory.getLogger(ERpcProxy.class);
	
	private Launcher launcher;
	
	public ERpcProxy(Launcher launcher) {
		super();
		this.launcher = launcher;
	}

	public <T> T create(Class<T> inter){
		return (T)Proxy.newProxyInstance(inter.getClassLoader(), new Class<?>[]{inter}, 
				(Object proxy, Method method, Object[] args) -> {
						ERpcRequestEntity eRpcRequestEntity = new ERpcRequestEntity();
						eRpcRequestEntity.setMsgId(UUID.randomUUID().toString());
						eRpcRequestEntity.setServiceName(method.getDeclaringClass().getSimpleName());
						eRpcRequestEntity.setMethodName(method.getName());
						ERpc annotation = method.getAnnotation(ERpc.class);
						if(annotation != null){
							try{
								eRpcRequestEntity.setArgs(setValue(args, ProtobufCache.get(annotation.req())).toByteArray());
								return launcher.write(eRpcRequestEntity, method.getReturnType()).getValue();
							}catch (Exception e) {
								logger.error("------", e);
							}
						}
						logger.error("class:{}, method:{} not exist ERpc annotation", method.getDeclaringClass().getName(), method.getName());
						
						return null;
				}
		);
	}
	
	
	public GeneratedMessageV3 setValue(Object[] args, GeneratedMessageV3 proto){
		GeneratedMessageV3.Builder builder =  (Builder) proto.getDefaultInstanceForType().newBuilderForType();
		List<FieldDescriptor> fields = proto.getDescriptorForType().getFields();
        int size = fields.size();
        if(size != args.length){
        	throw new RuntimeException("");
        }
        
        for (int i = 0; i < size; i++) {
			builder.setField(fields.get(i), args[i]);
		}
        return (GeneratedMessageV3) builder.build();
	}
}
